package myJs.user.centrifuge

import myJs.Implicits._
import myJs.Utils._
import myJs.myPkg.jquery._
import myJs.myPkg._
import myJs.tool.Pojo.FilterContentData
import myJs.tool.Tool
import myJs.tool.Tool.layerOptions
import org.scalajs.dom.ext.Ajax
import org.scalajs.dom._
import scalatags.Text.all.{value, _}
import scalatags.Text.{TypedTag, all}
import shared.VarTool

import scala.collection.immutable.SeqMap
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.scalajs.js
import scala.scalajs.js.Dynamic.{global => g}
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.annotation.{JSExport, JSExportTopLevel}
import scala.scalajs.js.{Date, JSON}

/**
 * Created by yz on 2019/4/25
 */
@JSExportTopLevel("MissionManage")
object MissionManage {

  val tableId = "table"
  val updateModalId = "updateModal"
  val formId = "form"
  val stateMap = SeqMap("success" -> "成功", "error" -> "失败", "running" -> "正在运行")

  def updateFormJq = $(s"#${updateModalId} #${formId}")

  @JSExport("init")
  def init = {
    initTable
    refreshTable
    updateMissionSocket
    registerEvent
    updateFormBootStrapValidator
  }

  def tableFilterEvent = {
    Tool.clickHide

    $(document.body).on("click", s".myOperate", "", (y: Element) => {
      MissionResult.filterContentShow(y)
    })
    $(document.body).on("click", s".mySortLi", "", (y: Element) => {
      Tool.execSort(y, "", () => {
        refreshTable
      })
    })
    $(document.body).on("click", s".myConfirm", "", (y: Element) => {
      Tool.confirmFilter(y, "", () => {
        refreshTable
      })
    })
    $(document.body).on("click", s".myHide", "", (y: Element) => {
      Tool.hideFilterContent(y)
    })
    $(document.body).on("click", s".myRemove", "", (y: Element) => {
      Tool.removeCondition(y, "", () => {
        refreshTable
      })
    })
    $(document.body).on("click", s".myRemoveSort", "", (y: Element) => {
      Tool.removeSort(y, "", () => {
        refreshTable
      })
    })
  }

  def registerEvent = {
    tableFilterEvent
    $(document.body).on("click", s".myDelete", "", (y: Element) => {
      val id = $(y).dataValue
      deleteData(id)
    })
    $(document.body).on("click", s".myUpdateShow", "", (y: Element) => {
      val id = $(y).dataValue
      updateShow(id)
    })
    $(document.body).on("click", s".myUpdate", "", (y: Element) => {
      update
    })
    $(s"#${updateModalId}").on("shown.bs.modal", () => {
      $(s"#${updateModalId} #${formId}").bv.revalidateField("missionName")
    })
  }

  def update = {
    val formJq = updateFormJq
    val bv = formJq.bv
    bv.validate()
    val valid = bv.isValid()
    if (valid) {
      val index = layer.alert(Tool.myElement, Tool.layerOptions)
      val url = g.jsRoutes.controllers.CentrifugeController.updateMission().url.toString
      val formData = formJq.serialize()
      Ajax.post(url = s"${url}", data = formData, headers = Map("Content-Type" -> "application/x-www-form-urlencoded"),
        responseType = "application/json").map { xhr =>
        refreshTable { () =>
          layer.close(index)
          $(s"#${updateModalId}").modal("hide")
          Swal.swal(SwalOptions.title("成功").text("修改成功!").`type`("success"))
        }
      }
    }
  }

  def updateShow(id: String) = {
    val url = g.jsRoutes.controllers.CentrifugeController.getMissionById().url.toString
    Ajax.get(url = s"${url}?missionId=${id}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val rs = xhr.responseText.toJDJAn
      updateFormJq.find("input[name='orignalMissionName']").`val`(rs.myGet("missionName"))
      updateFormJq.find("input[name='missionId']").`val`(rs.myGet("id"))
      $(s"#${updateModalId}").modal("show")
    }
  }

  def deleteData(id: String) = {
    val options = SwalOptions.title("").text("确定要删除此数据吗？").`type`("warning").showCancelButton(true).
      showConfirmButton(true).confirmButtonClass(Tool.confirmButtonClass).confirmButtonText("确定").closeOnConfirm(false).
      cancelButtonText("取消").showLoaderOnConfirm(true).cancelButtonClass(Tool.cancelButtonClass)
    Swal.swal(options, () => {
      execDelete(List(id))
    })
  }

  def execDelete(ids: List[String]) = {
    val data = js.Dictionary(
      "ids" -> ids.toJSArray
    )
    val url = g.jsRoutes.controllers.CentrifugeController.deleteMissions().url.toString
    Ajax.delete(url = s"${
      url
    }", data = JSON.stringify(data),
      headers = Map("Content-Type" -> "application/json"), responseType = "blob").map {
      xhr =>
        refreshTable(
          () => {
            Swal.swal(SwalOptions.title("成功").text(s"删除成功！").`type`("success"))
            Tool.getIds()
          }
        )
    }
  }

  def getColumnV(columnName: String, v: js.Any) = columnName match {
    case "state" =>
      stateMap(v.toString)
    case _ =>
      v.toString
  }

  def getTableRs = {
    val url = g.jsRoutes.controllers.CentrifugeController.getAllMission().url.toString
    Ajax.get(url = s"${url}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      xhr.responseText.toJArJDJAn
    }
  }

  def refreshTable: Any = {
    refreshTable(() => ())
  }

  def refreshTable(f: () => Any): Any = {
    getTableRs.map { tableRs =>
      val queryMap = Tool.getQueryMap("")
      val sortData = Tool.sortExec(tableRs, queryMap)
      val filterData = Tool.execFilter(sortData = sortData, queryMap = queryMap, getColumnV = getColumnV)
      $(s"#${tableId}").bootstrapTable("load", filterData)
      f()
    }

  }

  val operateColumn = js.Array(
    ColumnOptions.field("operate").title("数据操作").formatter(operateFmt).filterControl("clear")
  )

  val missionOperateColumn = js.Array(
    ColumnOptions.field("missionOperate").title("任务操作").formatter(missionOperateFmt).filterControl("clear")
  )

  def tbFmt(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[js.Any]) => {
    columnName match {
      case "missionName" => {
        val state = row("state")
        if (state == "success") {
          val detailUrl = g.jsRoutes.controllers.CentrifugeController.missionResultBefore().url.toString
          a(title := "详情", href := s"${detailUrl}?missionId=${row("id")}", cursor.pointer, target := "_blank",
            v.toString
          ).render
        } else v.toString
      }
      case "state" => {
        val state1 = if (List("success").contains(row("state"))) {
          span(cls := "label label-success", "成功 ")
        } else if (List("running").contains(row("state"))) {
          span("正在运行 ",
            img(cls := "runningImage", src := "/assets/images/running2.gif", width := 30, height := 20))
        } else if (List("wait", "preparing").contains(row("state"))) {
          span(
            span(cls := "label label-default", "排队中 "),
            all.raw("&nbsp;"),
            img(cls := "runningImage", src := "/assets/images/running2.gif", width := 30, height := 20))
        } else {
          span(cls := "label label-danger", "失败 ")
        }
        state1.toString()
      }
      case _ =>
        v
    }
  }

  def expStyle(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[Any]) => columnName match {
    case _ => js.Dictionary()
  }

  def initFilterContent(tabId: String, map: SeqMap[String, String]) = {
    val textSortDatas = List(
      FilterContentData("missionName", map("missionName")),
    )
    val select2SortDatas = List(
      FilterContentData("state", map("state"), List.empty),
    )
    val timeSortDatas = List(
      FilterContentData("startTime", map("startTime")),
      FilterContentData("endTime", map("endTime")),
    )
    Tool.initFilterContent(textSortDatas = textSortDatas, select2SortDatas = select2SortDatas,
      timeSortDatas = timeSortDatas, parentId = s"${tabId}")
    refreshSelect2
    Tool.dateInit
    textSortDatas ::: timeSortDatas ::: select2SortDatas
  }

  def refreshSelect2 = {
    refreshState
  }

  def refreshState = {
    val inputName = "state"
    val array = stateMap.map { case (id, text) =>
      js.Dictionary("text" -> text, "id" -> id)
    }
    val options = Select2Options.dictData(array.toJSArray).multiple(true).placeholder("点击选择")
    Tool.getInputByName(inputName).select2(options)
  }

  def initTable = {
    val map = SeqMap("missionName" -> "任务名", "state" -> "运行状态",
      "startTime" -> "开始日期", "endTime" -> "结束日期")
    val columnNames = map.keyList
    val allDatas = initFilterContent("", map)
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName)
      val style = expStyle(columnName)
      val basicOptions = ColumnOptions.field(columnName).title(title).sortable(true).cellStyle(style).formatter(fmt)
      val datepickerOptions: js.Dictionary[js.Any] = js.Dictionary("format" -> Tool.pattern, "language" -> "zh-CN",
        "autoclose" -> true)
      columnName match {
        case x if allDatas.map(_.fieldName).contains(x) => basicOptions.
          sortable(false).operateable(true)
        case _ => basicOptions
      }
    }.concat(operateColumn).concat(missionOperateColumn)
    val options = TableOptions.columns(columns.toJSArray).searchOnButton(false).filterControl(false)
    $(s"#${tableId}").bootstrapTable(options)
  }

  def operateFmt: js.Function = {
    (v: js.Any, row: js.Dictionary[js.Any]) =>

      val downloadUrl = g.jsRoutes.controllers.CentrifugeController.downloadResult().url.toString
      val downloadStr = a(title := "下载结果", href := s"${downloadUrl}?missionId=${row("id")}", cursor.pointer,
        span(em(cls := "fa fa-download"))
      )

      val downloadDataUrl = g.jsRoutes.controllers.CentrifugeController.downloadData().url.toString
      val downloadDataStr = a(title := "下载原始数据", href := s"${downloadDataUrl}?missionId=${row("id")}", cursor.pointer,
        span(em(cls := "fa fa-cloud-download"))
      )

      val state1 = if (List("success", "warning").contains(row("state"))) {
        List(downloadStr)
      } else List[TypedTag[String]]()
      val state2 = if (List("success", "error", "warning").contains(row("state"))) {
        List(downloadDataStr)
      } else List[TypedTag[String]]()
      val rs = state1 ::: state2
      rs.mkString("&nbsp;")
  }

  def missionOperateFmt: js.Function = {
    (v: js.Any, row: js.Dictionary[js.Any]) =>
      val updateNameStr = a(title := "修改任务名", `class` := "myUpdateShow",
        cursor.pointer, dataValue := s"${row("id")}",
        target := "_blank", span(em(cls := "fa fa-edit"))
      )
      val deleteStr = a(
        title := "删除",
        cursor.pointer,
        `class` := "myDelete", dataValue := s"${row("id")}",
        target := "_blank",
        span(
          em(cls := "fa fa-close")
        )
      )

      val viewStr = a(title := "日志", onclick := s"MissionManage.viewLog('${row("id")}')", cursor.pointer,
        span(em(cls := "fa fa-file-text"))
      )

      val reRunUrl = g.jsRoutes.controllers.CentrifugeController.reRunMissionBefore().url.toString
      val reRunStr = a(title := "重新运行", href := s"${reRunUrl}?missionId=${row("id")}", cursor.pointer,
        span(em(cls := "fa fa-refresh"))
      )

      val state1 = if (List("success", "warning").contains(row("state"))) {
        List(updateNameStr)
      } else List[TypedTag[String]]()
      val state2 = if (!List("running", "wait", "preparing").contains(row("state"))) {
        List(viewStr, reRunStr)
      } else List[TypedTag[String]]()
      val rs = state1 ::: state2 ::: List(deleteStr)
      rs.mkString("&nbsp;")
  }

  @JSExport("viewLog")
  def viewLog(id: String) = {
    val url = g.jsRoutes.controllers.CentrifugeController.getLogContent().url.toString
    Ajax.get(url = s"${url}?missionId=${id}", headers = Map("Content-Type" -> "application/json")).map { xhr =>
      val dict = xhr.responseText.toJDS
      val options = LayerOptions.`type`(1).title("<h4>运行信息</h4>").area(js.Array("900px", "600px")).
        skin("layui-layer-demo").closeBtn(1).anim(2).shadeClose(true).maxmin(true).
        content(s"<pre style='word-wrap: break-word' class='genome-pre'>${dict("str")}</pre>")
      layer.open(options)
    }
  }

  def updateMissionSocket = {
    val url = g.jsRoutes.controllers.CentrifugeController.updateMissionSocket().url.toString
    val wsUri = s"ws://${window.location.host}${url}"
    webSocket(wsUri)
  }

  def webSocket(wsUri: String) = {
    val websocket = new WebSocket(wsUri)
    websocket.onopen = (evt) =>
      websocket.send(JSON.stringify(js.Dictionary("info" -> "start")))
    websocket.onclose = (evt) =>
      println(s"ERROR:${evt.code},${evt.reason},${evt.wasClean}")
    websocket.onmessage = (evt) => {
      val message = evt.data
      val data = JSON.parse(message.toString).toJArJDS
      $(s"#${tableId}").bootstrapTable("load", data)
    }
    websocket.onerror = (evt) => {
      updateByHand
      println(s"ERROR:${evt.toString}")
    }
  }

  def updateByHand = {
    js.timers.setInterval(3000) {
      refreshTable
    }
  }

  def updateFormBootStrapValidator = {
    val url = g.jsRoutes.controllers.CentrifugeController.missionNameCheck().url.toString
    val dict: js.Dictionary[js.Any] = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> js.Dictionary(
        "missionName" -> js.Dictionary(
          "validators" -> js.Dictionary(
            "notEmpty" -> js.Dictionary(
              "message" -> "任务名不能为空!"
            ),
            "remote" -> js.Dictionary(
              "message" -> "任务名已存在!",
              "extension" -> "csv",
              "url" -> url,
              "type" -> "POST",
              "delay" -> 1000
            ),
          )
        ),
      )
    )
    updateFormJq.bootstrapValidator(dict)

  }


}
